package com.wbl.train.business.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wbl.train.business.service.TrainCarriageService;
import com.wbl.train.common.business.dto.TrainSeatDto;
import com.wbl.train.common.business.entity.TrainCarriageEntity;
import com.wbl.train.common.business.entity.TrainSeatEntity;
import com.wbl.train.business.mapper.TrainSeatMapper;
import com.wbl.train.business.service.TrainSeatService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wbl.train.common.business.enums.SeatColEnum;
import com.wbl.train.common.exception.ApplicationException;
import com.wbl.train.common.page.PageVo;
import com.wbl.train.common.result.ResultCode;
import com.wbl.train.common.utils.SnowUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * 座位 服务实现类
 * @author 王博纶
 * @since 2024-02-02
 */
@AllArgsConstructor
@Slf4j
@Service
public class TrainSeatServiceImpl extends ServiceImpl<TrainSeatMapper, TrainSeatEntity> implements TrainSeatService {

    private final TrainCarriageService trainCarriageService;

    @Override
    public PageVo<TrainSeatEntity> queryTrainSeat(TrainSeatDto trainSeatDto) {
        // 获取分页所需要的参数
        int page = trainSeatDto.getPage();
        int limit = trainSeatDto.getLimit();

        LambdaQueryWrapper<TrainSeatEntity> trainSeatWrapper = new LambdaQueryWrapper<TrainSeatEntity>()
                .orderByAsc(TrainSeatEntity::getTrainCode) // 按照 trainCode 升序排序
                .orderByAsc(TrainSeatEntity::getCarriageIndex) // 按照carriageIndex 车厢序号 升序排序
                .orderByAsc(TrainSeatEntity::getCarriageSeatIndex) // 按照carriageSeatIndex 车厢座位号 升序排序
                // 根据trainCode进行过滤，有值就过滤，没有值不拼接条件
                .eq(ObjectUtil.isNotEmpty(trainSeatDto.getTrainCode()),TrainSeatEntity::getTrainCode,trainSeatDto.getTrainCode());
        //创建分页对象
        IPage<TrainSeatEntity> trainSeatPage = new Page<>(page,limit);
        //调用分页方法
        IPage<TrainSeatEntity> trainSeatPageData = page(trainSeatPage,trainSeatWrapper);
        // 获取查询出来的数据集合
        List<TrainSeatEntity> records = trainSeatPageData.getRecords();
        // 将数据塞到PageVo类中并返回出去
        return new PageVo<TrainSeatEntity>()
                .setDataList(records)
                .setPageSize(limit).setCurrentPage(page)
                .setTotal((int) trainSeatPageData.getTotal())
                .setPages((int) trainSeatPageData.getPages());
    }

    @Override
    public boolean insertAndUpdateTrain(TrainSeatEntity trainSeat) {
        // 获取当前的时间 --- 用于创建和修改的时候的时间填充
        DateTime now = DateTime.now();
        // 设置火车车厢座位的修改时间
        trainSeat.setUpdateTime(now);
        // 判断Id是否为空
        if(ObjectUtil.isNotNull(trainSeat.getId())){
            // 根据id查询火车车厢座位信息
            TrainSeatEntity trainSeatEntity = this.getById(trainSeat.getId());
            // 当前id对应的无火车车厢座位信息
            if(ObjectUtil.isNull(trainSeatEntity)){
                throw new ApplicationException(ResultCode.DATA_NOT_EXIST,"当前火车车厢座位不存在");
            }
            // 更新火车车厢座位信息
            return this.updateById(trainSeat);
        }
        // 给新增的火车车厢座位设置Id，创建时间和修改时间
        trainSeat.setId(SnowUtil.getSnowflakeNextId())
                .setCreateTime(now);
        // 新增火车车厢座位
        return this.save(trainSeat);
    }

    @Transactional
    public void generateSeat(String trainCode){
        DateTime now = DateTime.now();
        // 初始化一个用于批量新增座位的结合
        ArrayList<TrainSeatEntity> seatEntityList = new ArrayList<>();
        if(ObjectUtil.isEmpty(trainCode)){
            throw new ApplicationException(ResultCode.PARAM_REQUIRE,"trainCode不能为空");
        }
        LambdaQueryWrapper<TrainSeatEntity> wrapper = new LambdaQueryWrapper<TrainSeatEntity>()
                .eq(TrainSeatEntity::getTrainCode, trainCode);
        // 先删除当前车次下的所有的座位记录
        this.remove(wrapper);
        // 查找当前车次下的所有车厢
        List<TrainCarriageEntity> carriageList = trainCarriageService.selectByTrainCode(trainCode);
        log.info("当前车次下的车厢数:{}",carriageList.size());
        // 循环车厢，生成对应车厢下的座位
        for (TrainCarriageEntity trainCarriage : carriageList) {
            // 获取车厢：行数、座位类型（根据座位类型获取列数）
            Integer rowCount = trainCarriage.getRowCount(); // 行数
            String seatType = trainCarriage.getSeatType(); // 座位类型
            int seatIndex = 1;
            // 根据座位类型筛选出所的列
            List<SeatColEnum> seatCols = SeatColEnum.getColsByType(seatType);
            log.info("根据车厢的座位类型，筛选出所有的列:{}",seatCols);
            // 循环行数
            for (int row = 1; row <= rowCount; row++) {
                // 循环列数
                for (SeatColEnum seatCol : seatCols) {
                    // 构造座位数据并保存到数据库 --- 并添加到对应的集合中，用于批量新增
                    TrainSeatEntity trainSeatEntity = new TrainSeatEntity();
                    seatEntityList.add(trainSeatEntity
                            .setId(SnowUtil.getSnowflakeNextId()) // id
                            .setTrainCode(trainCode) // 车次编号
                            .setCarriageIndex(trainCarriage.getCarriageIndex()) // 车厢序号
                            .setSeatRow(StrUtil.fillBefore(String.valueOf(row), '0', 2)) // 座位行数
                            .setSeatCol(seatCol.getCode()) // 座位列数
                            .setSeatType(seatType) // 座位类型
                            .setCarriageSeatIndex(seatIndex++) // 车厢座位序号
                            .setCreateTime(now) // 创建时间
                            .setUpdateTime(now) // 修改时间
                    );
                }
            }
        }
        log.info("准备生成的座位数量:{}",seatEntityList.size());
        // 批量新增座位数据
        this.saveBatch(seatEntityList);
    }


    public List<TrainSeatEntity> selectByTrainCode(String trainCode){
        LambdaQueryWrapper<TrainSeatEntity> wrapper = new LambdaQueryWrapper<TrainSeatEntity>()
                .eq(TrainSeatEntity::getTrainCode, trainCode)
                .orderByAsc(TrainSeatEntity::getCarriageIndex);
        return this.list(wrapper);
    }
}
